package org.hackystat.devcathlon.engine.event.impl;

import static org.junit.Assert.assertEquals;
import javax.xml.datatype.XMLGregorianCalendar;
import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.engine.event.Event;
import org.hackystat.devcathlon.engine.event.EventScore;
import org.hackystat.devcathlon.engine.match.Match;
import org.hackystat.devcathlon.engine.team.Team;
import org.hackystat.devcathlon.engine.test.DevcathlonTestHelper;
import org.hackystat.devcathlon.engine.user.User;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * Tests the Build Everyday event.
 * @author robin
 *
 */
public class TestEveryoneBuild extends DevcathlonTestHelper {
  
  /** The bonus weight. */
  private static int bonusWeight = 10;
  /** The penalty weight. */
  private static int penaltyWeight = -10;
  
  private static int dayStreak = 7;
  
  private String teamName = "TestTeam";
  private String teamOwner = "TeamOwner";
  private String matchName = "TestMatch";
  private String member1 = "Member1";
  private String member2 = "Member2";
  private String member3 = "Member3";
  
  /**
   * Sets up the DevcathlonConfiguration for use in these test cases. 
   * @throws Exception If problems occur setting up the configuration. 
   */
  @BeforeClass
  public static void setupConfiguration() throws Exception {
    
    // Set up the testing DevcathlonConfiguration for the event EveryoneBuilds.
    String eventName = EveryoneBuild.eventName;
    ConfigurationManager configManager = ConfigurationManager.getInstance();
    configManager.setBaseScoreWeight(eventName, 10);
    configManager.getConfiguration(eventName);
    configManager.setWakeupInterval(eventName, 1440);
    configManager.addProperty(eventName, EveryoneBuild.bonusWeightKey, String.valueOf(bonusWeight));
    configManager.addProperty(eventName, EveryoneBuild.penaltyWeightKey, 
        String.valueOf(penaltyWeight));
    configManager.addProperty(eventName, EveryoneBuild.dayStreakKey, 
        String.valueOf(dayStreak));
  }
  
  /**
   * Tests this event when there is no build for this team.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testNoBuildData() throws Exception {
    
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2, member3);
    
    // Now create the event instance.
    Event event = new EveryoneBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    // Test the event with no sensor data.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 0", -70, score.getBaseScore());
    assertEquals("Check bonus 0", 0, score.getBonusScore(EveryoneBuild.bonusWeightKey));
    assertEquals("Check points 0", -70, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when only one member builds for 3 out of 7 days.
   * @throws Exception If there is a bug.
   */

  @Test
  public void testSingleBuildData() throws Exception {
    
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2, member3);
    
    // Now create the event instance.
    Event event = new EveryoneBuild();
    // Create a simple match containing a single team, a single project, and this event.
    
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    XMLGregorianCalendar currTime = Tstamp.makeTimestamp();
    
    // Send a single build data. 
    makeBuildData(team.getOwner(), project, Tstamp.incrementDays(currTime, -5));
    makeBuildData(team.getOwner(), project, Tstamp.incrementDays(currTime, -2));
    makeBuildData(team.getOwner(), project, Tstamp.incrementDays(currTime, -1));
    makeBuildData(team.getOwner(), project, Tstamp.incrementDays(currTime, -1));
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp());
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp());
    
    // Test the event with no sensor data.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    
    // Now compute the event score.
    assertEquals("Check base 1", -30, score.getBaseScore());
    assertEquals("Check bonus 1", 0, score.getBonusScore(EveryoneBuild.bonusWeightKey));
    assertEquals("Check points 1", -30, event.computePoints(score));

    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there is only one day where all members build. 
   * @throws Exception If there is a bug.
   */

  @Test
  public void testAllMemberBuild() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    XMLGregorianCalendar startTime = Tstamp.makeTimestamp();
    // Now create the event instance.
    Event event = new EveryoneBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    
    // Make single build data for project owner. 
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp());
    
    // Make 7 day streak for other members of team.
    for (int i = -7; i < 1; i++) {
      for (User users : team.getMembers()) {
        makeBuildData(users, project, Tstamp.incrementDays(startTime, i));
      }
    }
    
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 2", 10, score.getBaseScore());
    assertEquals("Check bonus 2", 0, score.getBonusScore(EveryoneBuild.bonusWeightKey));
    assertEquals("Check points 2", 10, event.computePoints(score));

    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }

  /**
   * Test this event where all members build for 7 consecutive days.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testNonProjectOwner() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1);
    XMLGregorianCalendar startTime = Tstamp.makeTimestamp();
    // Now create the event instance.
    Event event = new EveryoneBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    
    // Make 7 day streak build data for all members.
    for (int i = -7; i < 1; i++) {
      for (User users : team.getMembers()) {
        makeBuildData(team.getOwner(), project, Tstamp.incrementDays(startTime, i));
        makeBuildData(users, project, Tstamp.incrementDays(startTime, i));
      }
    }
    
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 3", 70, score.getBaseScore());
    assertEquals("Check bonus 3", 10, score.getBonusScore(EveryoneBuild.bonusWeightKey));
    assertEquals("Check points 3", 80, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there 6 consecutive days with all members building. 
   * @throws Exception If there is a bug.
   */

  @Test
  public void testSixAllMemberBuild() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    XMLGregorianCalendar startTime = Tstamp.makeTimestamp();
    // Now create the event instance.
    Event event = new EveryoneBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    // Make 7 day streak for other members of team.
    for (int i = -5; i < 1; i++) {
      for (User users : team.getMembers()) {
        makeBuildData(team.getOwner(), project, Tstamp.incrementDays(startTime, i));
        makeBuildData(users, project, Tstamp.incrementDays(startTime, i));
      }
    }
    
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 4", 50, score.getBaseScore());
    assertEquals("Check bonus 4", 0, score.getBonusScore(EveryoneBuild.bonusWeightKey));
    assertEquals("Check points 4", 50, event.computePoints(score));

    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
}